package com.gitee.booting.dspi.autoconfigure;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.gitee.booting.balancer4j.RoundRobinLoadBalancer;
import com.gitee.booting.dspi.Endpoint;
import com.gitee.booting.dspi.Extensions;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.MultipartConfigElement;
import java.util.Collection;
import java.util.Map;

@Configuration
public class DspiAutoConfiguration {

    @Bean
    public ServletRegistrationBean<DispatcherServlet> extensionServlet(WebApplicationContext applicationContext) {
        AnnotationConfigWebApplicationContext dispatcherServletConfiguration = new AnnotationConfigWebApplicationContext();
        dispatcherServletConfiguration.setParent(applicationContext);
        dispatcherServletConfiguration.register(Endpoint.class);
        DispatcherServlet servlet = new DispatcherServlet(dispatcherServletConfiguration);
        ServletRegistrationBean<DispatcherServlet> registrationBean =
            new ServletRegistrationBean<>(servlet, Extensions.ENDPOINT + "/*");
        registrationBean.setName("Extension Service Servlet");
        registrationBean.setMultipartConfig(new MultipartConfigElement((String) null));
        registrationBean.setLoadOnStartup(1);
        registrationBean.setAsyncSupported(true);
        return registrationBean;
    }


    @Bean
    @ConditionalOnMissingBean
    public Extensions extensions(RestTemplateBuilder builder, DiscoveryClient client,
                                 ApplicationContext context,
                                 NacosDiscoveryProperties properties) throws ClassNotFoundException {
        ClassLoader cl = this.getClass().getClassLoader();
        for (Map.Entry<String, String> entry : properties.getMetadata().entrySet()) {
            String c = entry.getKey();
            String ni = entry.getValue();
            String[] services = ni.split(Extensions.COMMA);
            String[] kv;
            try {
                Class<?> type = cl.loadClass(c);
                Collection<?> instances = context.getBeansOfType(type).values();
                Class<?> provider;
                boolean found;
                for (String service : services) {
                    kv = service.split(Extensions.SERVICE_NAME_SEPARATOR);
                    if (kv.length == 1) {
                        provider = cl.loadClass(kv[0]);
                    } else {
                        provider = cl.loadClass(kv[1]);
                    }
                    found = false;
                    for (Object instance : instances) {
                        if (provider.isAssignableFrom(instance.getClass())) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        throw new RuntimeException("Service instance [" + c + "/" + service + "] not found.");
                    }
                }
            } catch (ClassNotFoundException ignore) {
            }
        }
        return new Extensions().init(builder.build(), client, new RoundRobinLoadBalancer());
    }

}
